const Pokers = require("./Pokers");

class Game extends Pokers {
  constructor(players, socket) {
    super();  //继承自扑克牌对象
    this.players = players; //接收玩家数组
    this.socket = socket; //接收socket对象
    this.cardsArr = []; //存储玩家出过的牌
    this.cards = null; //存储当前出的牌
    this.integral = 0; //当前回合制积分
    this.roundCount = 0; //回合制计数，出牌次数
    this.startGame();
  }
  // 开局
  startGame() {
    this.upset(); //洗牌
    let playerName = '';
    // 遍历玩家，对每个玩家操作(触发每个玩家自带的方法)
    this.players.forEach((player, index) => {
      player.order = index + 1; //出牌顺序
      // 第一位玩家先出牌
      if (player.order === 1) {
        player.firstFlag = true;
        player.firstPlay();
        player.flag = true;
        playerName = player.name
      }
    })
    this.players.forEach(player => {
      let pokers = this.sysLicensing(7); //系统切牌
      player.initPlayState(); //初始化玩家状态
      player.licensing(pokers, player); //发牌
    })
    this.sysLicensingStatus();  //发牌
    // 出牌提示放在发牌后，不然拿不到数据
    this.players.forEach(player => {
      player.chupai(playerName); //出牌提示
      player.animation(); //交互动画
      player.playCards(); //监听出牌
    })
    // await this.round(); //开始回合制
  }
  // 回合制
  async round() {
    return new Promise((resolve, reject) => {
      // 需要监听的属性，firstFlag,flag
      const _this = this;
      const [player1, player2, player3, player4] = this.players; //解构出四个玩家对象
      let awaitCount = 0; //等待对局结束的玩家个数
      let awaitGame = 0; //等待对局结束的玩家个数

      this.players.forEach(async player => {
        if (player.firstFlag) {
          player.flag = true;
          player.chupai();
        }
        player.playCards()
      })

      // 监听系统牌的长度，如果长度为空返回结果
      Object.defineProperties(_this, {
        // 扑克牌
        "pokers": {
          set(val) {
            this.pokers = val; //赋值
            // let endGame = val.length == 0 && player1.pokers.length == 0 && player2.pokers.length == 0 && player3.pokers.length == 0 && player4.pokers.length == 0;
            // 结束对局标志：系统没有牌并且等待对局结束的玩家个数为3
            let endGame = val.length == 0 && awaitGame == 3;
            if (endGame) {
              resolve("对局结束！");
            }
          }
        },
        // 出牌次数
        "roundCount": {
          set(val) {
            roundCount = val; //赋值
            if (val % 4 === 0) {
              // 发牌状态
              this.sysLicensingStatus();
            }
          }
        }
      })

      // 监听对象属性
      // 玩家1
      Object.defineProperties(player1, {
        "flag": {
          async set(val) {
            this.flag = val; //赋值
            //其他人都过牌，轮空、完成一个回合制，该玩家重新出牌
            let check = this.flag && player2.check && player3.check && player4.check;
            // 其他玩家没有过牌，并且自己轮到自己出牌，手里牌已经没有了并且系统牌不为空，就可以发牌
            let nullCards = this.flag && this.pokers.length == 0 && _this.pokers.length != 0 || !player2.check || !player3.check || !player4.check;
            // 玩家手中没有牌，系统牌也空了，就该等待对局结束
            let awaitGame = this.pokers.length == 0 && _this.pokers.length == 0;

            // 玩家赢了，等待对局结束，不用往下执行
            if (awaitGame) {
              awaitCount++;  //加入等待列表
              return this.awaitGameEnd();  //等待对局结束
            }

            if (val) {
              // 回合制，开始发牌，补牌
              if (check) {
                _this.players.forEach(async player => {
                  if (player.pokers.length == 7) return; //如果玩家手里有七张牌，就不用发牌
                  let leng = 7 - player.pokers.length; //需要发几张牌
                  let pokers = _this.sysLicensing(leng); //系统切牌
                  player.licensing(pokers, player)
                })
                _this.cards = this.playCards(_this.cards, check); //执行玩家的出牌方法
              }
              // 轮到玩家出牌，手里牌是空的，系统发牌，补牌
              else if (nullCards) {
                let pokers = _this.sysLicensing(7); //系统切牌
                player.licensing(pokers, player)
              }
              // 正常出牌
              else {
                _this.cards = this.playCards(_this.cards); //执行玩家的出牌方法
                // 出牌广播
                _this.players.forEach(player => {
                  player.sysPlayCards(_this.cards);
                })
              }
              player2.flag = true; //触发下一个玩家出牌
              _this.cardsArr.push(_this.cards); //将出过的牌放入数组存起来
            }
          }
        }
      })
      // 玩家2
      Object.defineProperties(player2, {
        "flag": {
          async set(val) {
            this.flag = val; //赋值
            //其他人都过牌，轮空、完成一个回合制，该玩家重新出牌
            let check = this.flag && player1.check && player3.check && player4.check;
            // 其他玩家没有过牌，并且自己轮到自己出牌，手里牌已经没有了并且系统牌不为空，就可以发牌
            let nullCards = this.flag && this.pokers.length == 0 && _this.pokers.length != 0 || !player1.check || !player3.check || !player4.check;
            // 玩家手中没有牌，系统牌也空了，就该等待对局结束
            let awaitGame = this.pokers.length == 0 && _this.pokers.length == 0;

            // 玩家赢了，等待对局结束，不用往下执行
            if (awaitGame) {
              awaitCount++;  //加入等待列表
              return this.awaitGameEnd();  //等待对局结束
            }

            if (val) {
              // 回合制，开始发牌，补牌
              if (check) {
                _this.players.forEach(async player => {
                  if (player.pokers.length == 7) return; //如果玩家手里有七张牌，就不用发牌
                  let leng = 7 - player.pokers.length; //需要发几张牌
                  let pokers = _this.sysLicensing(leng); //系统切牌
                  player.licensing(pokers, player)
                })
                _this.cards = this.playCards(_this.cards, check); //执行玩家的出牌方法
              }
              // 轮到玩家出牌，手里牌是空的，系统发牌，补牌
              else if (nullCards) {
                let pokers = _this.sysLicensing(7); //系统切牌
                player.licensing(pokers, player)
              }
              // 正常出牌
              else {
                _this.cards = this.playCards(_this.cards); //执行玩家的出牌方法
                _this.players.forEach(player => {
                  player.sysPlayCards(_this.cards);
                })
              }
              player3.flag = true; //触发下一个玩家出牌
              _this.cardsArr.push(_this.cards); //将出过的牌放入数组存起来
            }
          }
        }
      })
      // 玩家3
      Object.defineProperties(player3, {
        "flag": {
          async set(val) {
            this.flag = val; //赋值
            //其他人都过牌，轮空、完成一个回合制，该玩家重新出牌
            let check = this.flag && player1.check && player2.check && player4.check;
            // 其他玩家没有过牌，并且自己轮到自己出牌，手里牌已经没有了并且系统牌不为空，就可以发牌
            let nullCards = this.flag && this.pokers.length == 0 && _this.pokers.length != 0 || !player1.check || !player2.check || !player4.check;
            // 玩家手中没有牌，系统牌也空了，就该等待对局结束
            let awaitGame = this.pokers.length == 0 && _this.pokers.length == 0;

            // 玩家赢了，等待对局结束，不用往下执行
            if (awaitGame) {
              awaitCount++;  //加入等待列表
              return this.awaitGameEnd();  //等待对局结束
            }

            if (val) {
              // 回合制，开始发牌，补牌
              if (check) {
                _this.players.forEach(async player => {
                  if (player.pokers.length == 7) return; //如果玩家手里有七张牌，就不用发牌
                  let leng = 7 - player.pokers.length; //需要发几张牌
                  let pokers = _this.sysLicensing(leng); //系统切牌
                  player.licensing(pokers, player)
                })
                _this.cards = this.playCards(_this.cards, check); //执行玩家的出牌方法
              }
              // 轮到玩家出牌，手里牌是空的，系统发牌，补牌
              else if (nullCards) {
                let pokers = _this.sysLicensing(7); //系统切牌
                player.licensing(pokers, player)
              }
              // 正常出牌
              else {
                _this.cards = this.playCards(_this.cards); //执行玩家的出牌方法
                _this.players.forEach(player => {
                  player.sysPlayCards(_this.cards);
                })
              }
              player4.flag = true; //触发下一个玩家出牌
              _this.cardsArr.push(_this.cards); //将出过的牌放入数组存起来
            }
          }
        }
      })
      // 玩家4
      Object.defineProperties(player4, {
        "flag": {
          async set(val) {
            this.flag = val; //赋值
            //其他人都过牌，轮空、完成一个回合制，该玩家重新出牌
            let check = this.flag && player1.check && player2.check && player3.check;
            // 其他玩家没有过牌，并且自己轮到自己出牌，手里牌已经没有了并且系统牌不为空，就可以发牌
            let nullCards = this.flag && this.pokers.length == 0 && _this.pokers.length != 0 || !player1.check || !player2.check || !player3.check;
            // 玩家手中没有牌，系统牌也空了，就该等待对局结束
            let awaitGame = this.pokers.length == 0 && _this.pokers.length == 0;

            // 玩家赢了，等待对局结束，不用往下执行
            if (awaitGame) {
              awaitCount++;  //加入等待列表
              return this.awaitGameEnd();  //等待对局结束
            }

            if (val) {
              // 回合制，开始发牌，补牌
              if (check) {
                _this.players.forEach(async player => {
                  if (player.pokers.length == 7) return; //如果玩家手里有七张牌，就不用发牌
                  let leng = 7 - player.pokers.length; //需要发几张牌
                  let pokers = _this.sysLicensing(leng); //系统切牌
                  player.licensing(pokers, player)
                })
                _this.cards = this.playCards(_this.cards, check); //执行玩家的出牌方法
              }
              // 轮到玩家出牌，手里牌是空的，系统发牌，补牌
              else if (nullCards) {
                let pokers = _this.sysLicensing(7); //系统切牌
                player.licensing(pokers, player)
              }
              // 正常出牌
              else {
                _this.cards = this.playCards(_this.cards); //执行玩家的出牌方法
                _this.players.forEach(player => {
                  player.sysPlayCards(_this.cards);
                })
              }
              player2.flag = true; //触发下一个玩家出牌
              _this.cardsArr.push(_this.cards); //将出过的牌放入数组存起来
            }
          }
        }
      })

    });
  }
  // 重新开始回合制
  roundAgain(result) {
    // 代表回合制结束，重新开始下一回合
    if (result.checkAll) {
      this.players[result.playerIndex].firstFlag = true;
      this.players[result.playerIndex].integral = result.integral;
      this.players[result.playerIndex].firstPlay();
      this.players.forEach(player => {
        player.integralMsg(result.playerName, result.integral)
      })
    }
    this.players[result.playerIndex].flag = true;
    this.players.forEach(player => {
      player.chupai(result.playerName)
    })
  }
  // 回合制副本
  roundCope(_this, data) {
    // let p = this.players; //玩家数组
    // let i = p.indexOf(_this);  //下标
    _this.outCard(data)
      .then(resolve => {
        _this.flag = false;
        if (resolve != "check") {
          this.cards = resolve; //当前出过的牌
          this.cardsArr.push(resolve);  //一轮回合中所出过的牌
        }
        let result = this.detection(_this); //检测对局
        result.checkAll && this.fillCards(result); //补牌
        this.roundAgain(result); //下一轮回合制
        // let playerName = '';
        // if(resolve == 'check'){
        //   if(i >= p.length - 1) {
        //     p[0].flag = true;
        //     playerName = p[0].name;
        //   }else {
        //     p[i + 1].flag = true;
        //     playerName = p[i + 1].name;
        //   }
        //   p.forEach(item =>{
        //     item.chupai(playerName);  //触发出牌通知
        //   })
        // }else{
        //   let check = this.fillCards(); //发牌检测
        //   // 出牌顺序
        //   if(i >= p.length - 1){
        //     // 当前全部过牌，结束本回合，进行下一轮回合
        //     if(check){
        //       p[0].firstFlag = true;  //设置首出玩家
        //       p[0].integral = this.integral;  //积分赋值
        //       this.integral = 0;  //重置积分
        //       this.players.forEach(player =>{
        //         player.integralMsg(playerName,this.integral);
        //       })
        //       p[0].firstPlay(); //触发消息通知
        //     }
        //     p[0].flag = true;
        //     playerName = p[0].name; //保存名字
        //   } else{
        //     if(check){
        //       p[i + 1].firstFlag = true;
        //       p[i + 1].firstPlay();
        //     }
        //     p[i + 1].flag = true;
        //     playerName = p[i + 1].name;
        //   }
        //   p.forEach(item =>{
        //     item.chupai(playerName);  //触发出牌通知
        //   })
        // }
      }, reject => {
        console.log(reject);
      }).catch(e => {
        console.log(e);
      })
  }
  // 检验
  detection(self) {
    // let p = this.players; //玩家数组
    let i = this.players.indexOf(self);  //下标
    let check = 0; //过牌
    let playerIndex = 0; //首次玩家下标或者下一个将要出牌的玩家
    let result = {}; //返回结果
    let integral = 0; //积分
    let leftOver = 0; //场内需要补牌数总数
    const cardsTotal = 28;  //场内玩家手里牌总数  4*7=28
    this.players.forEach((player, index) => {
      player.check && check++;
      // 取出将要首次出牌的玩家的下标
      if (player.prePlayCards && player.prePlayCards != 'check') {
        playerIndex = index;
      }
      leftOver += player.pokers.length;
    })
    leftOver = cardsTotal - leftOver; //总量减去玩家手里牌
    if (check == 3) {
      // 积分赋值 ---> 先判断当前回合是否存在积分牌再取出
      this.cardsArr.some(item => item.integral > 0) &&
        this.cardsArr.forEach(item => {
          if (item.integral > 0) {
            integral += item.integral;
          }
        })
      this.cardsArr.length = 0; //清空出过的牌
      result = {
        checkAll: true, //全部过牌
        playerIndex,  //首次出牌玩家索引
        playerName: this.players[playerIndex].name, //首次出牌玩家名字
        integral, //当前回合制总积分
        leftOver  //当前回合制场内玩家剩余牌总量
      }
    } else {
      // 按顺序往下执行出牌顺序
      result = (i >= this.players.length - 1) ?
        { checkAll: false, playerIndex: 0, playerName: this.players[0].name, integral: 0, leftOver } :
        { checkAll: false, playerIndex: i + 1, playerName: this.players[i + 1].name, integral: 0, leftOver }
    }
    return result;
  }
  // 补牌
  fillCards(result) {
    // let check = 0; //过牌
    // let checkAll = false; //是否全部过牌
    // this.players.forEach(player =>{
    //   player.check && check++;
    // })
    // console.log(check,"过牌数量");
    // 判断剩余牌面
    // 剩余牌面为0
    if (this.pokers.length == 0) {
      this.players.forEach(player => {
        if (player.pokers.length == 0) player.waitGameEnd = true;
      })
    } 
    // 剩余牌面足够补牌
    else if (this.pokers.length > 0 && this.pokers.length > result.leftOver) {
      // 回合制刷新
      this.players.forEach(player => {
        player.check = false; //重置过牌
        //如果玩家手里有七张牌，就不用发牌
        if (player.pokers.length == 7) return;
        else {
          let leng = 7 - player.pokers.length; //需要发几张牌
          let pokers = this.sysLicensing(leng); //系统切牌
          player.licensing(pokers); //发牌
        }
      })
      this.sysLicensingStatus();
    }
    // 剩余牌面不够补牌
    else if (this.pokers.length > 0 && this. pokers.length < result.leftOver) {
      // 保存首次出牌玩家索引
      let index = result.playerIndex;
      this.recursiveCard(index);
      this.players.forEach(player => {
        player.check = false;
      })
      this.sysLicensingStatus();
    }
    // // 三个过牌
    // if(check == 3){
    //   checkAll = true;
    //   // 积分赋值 ---> 先判断当前回合是否存在积分牌再取出
    //   this.cardsArr.some(item => item.integral > 0) &&
    //   this.cardsArr.forEach(item =>{
    //     if(item.integral > 0){
    //       this.integral += item.integral;
    //     }
    //   })
    //   // 回合制刷新
    //   this.players.forEach(player => {
    //     player.check = false; //重置过牌
    //     //如果玩家手里有七张牌，就不用发牌
    //     if (player.pokers.length == 7) return;
    //     else if(this.pokers.length == 0 && player.pokers.length == 0){
    //       player.waitGameEnd = true;
    //     }else{
    //       let leng = 7 - player.pokers.length; //需要发几张牌
    //       let pokers = this.sysLicensing(leng); //系统切牌
    //       player.licensing(pokers); //发牌
    //     }
    //   })
    //   this.sysLicensingStatus();
    //   return checkAll;
    // }else{
    //   checkAll = false;
    //   return checkAll;
    // }
  }
  // 递归补牌
  recursiveCard(index){
    // index标识为玩家在数组中的位置
    // 拿到需要补牌的数量，如果需要补牌的数量小于场内牌面数量照常发，如果大于则把剩下的牌发完
    let fillCardsLength = 7 - this.players[index].pokers.length < this.pokers.length ?
      7 - this.players[index].pokers.length : this.pokers.length;
    // 系统切牌 
    let pokers = this.sysLicensing(fillCardsLength);
    // 玩家补牌
    this.players[index].licensing(pokers)
    // 如果是数组中最后一个玩家，则从零开始，不是就加一往下递归
    index = index >= this.players.length -1 ? 0 : index + 1;
    // 这里即是递归，停止条件为场内牌面不为零并且没有第二次轮到首次补牌的玩家
    // 因为第一次补牌的玩家的 flag 一定是为 true，其他的玩家 flag 一定为 false，
    // 到这里的 index 已经是下一位玩家了，所以递归到最后的那一个一定是首次补牌的玩家的上一家
    if(this.pokers.length && !this.players[index].flag){
      this.recursiveCard(index);
    }
  }
  // 定胜负
  referee() {

  }
  // 结束对局
  endGame() {

  }
  // 系统发牌状态   -->  待优化
  sysLicensingStatus() {
    const [player1, player2, player3, player4] = this.players; //解构出四个玩家对象
    player1.cardsCount([
      { order: player1.order, pokers: player1.pokers, name: player1.name },
      { order: player2.order, pokers: player2.pokers.length, name: player2.name },
      { order: player3.order, pokers: player3.pokers.length, name: player3.name },
      { order: player4.order, pokers: player4.pokers.length, name: player4.name },
    ])
    // 状态
    player2.cardsCount([
      { order: player2.order, pokers: player2.pokers, name: player2.name },
      { order: player3.order, pokers: player3.pokers.length, name: player3.name },
      { order: player4.order, pokers: player4.pokers.length, name: player4.name },
      { order: player1.order, pokers: player1.pokers.length, name: player1.name },
    ])
    // 状态
    player3.cardsCount([
      { order: player3.order, pokers: player3.pokers, name: player3.name },
      { order: player4.order, pokers: player4.pokers.length, name: player4.name },
      { order: player1.order, pokers: player1.pokers.length, name: player1.name },
      { order: player2.order, pokers: player2.pokers.length, name: player2.name },
    ])
    // 状态
    player4.cardsCount([
      { order: player4.order, pokers: player4.pokers, name: player4.name },
      { order: player1.order, pokers: player1.pokers.length, name: player1.name },
      { order: player2.order, pokers: player2.pokers.length, name: player2.name },
      { order: player3.order, pokers: player3.pokers.length, name: player3.name },
    ])
  }
}

module.exports = Game;